"use strict";
const fs = require("fs");
const assert = require("assert");
const path = require("path");

const cfg = require("./config/server");
const tool = require("./lib/common");
const signature = require("./lib/signature");
const retry = require("./lib/retry");

const defaultKey = cfg.key;
const defaultSecret = cfg.secret;
const defaultServer = cfg.resourceServer.url;
const defaultVersion = cfg.resourceServer.version;
const generalUploadFile = function(file) {

	const getSignature = () => signature.encrypt(this.rawSignature);
	const getRequestOptions = (signature) => {
		const param = {
			key: this.key,
			time: this.time,
			token: signature,
			contentType: "multipart/form-data"
		};
		return {
			url: this.url,
			method: "POST",
			headers: tool.getHeaders(param),
			formData: tool.getFormData(file),
			json: true
		};
	};
	const upload = options => {
		console.log("上传文件的options是", tool.inspect(options, 2));
		return tool.sendRequest(options);
	};
	return getSignature().then(getRequestOptions).then(upload);
};

const uploadFile = function(file) {
	assert.ok(file, "please provide file object for upload");
	assert.ok(file.path, "please provide file path for upload");
	const localFile = {
		path: file.path,
		name: file.name || path.basename(file.path),
		contentType: file.contentType || "application/octet-stream"
	};
	const time = Date.now();
	const fileSize = fs.statSync(file.path).size;
	const ctx = {
		key: this.key,
		secret: this.secret,
		url: `${this.resourceServer}/${this.version}?file_size=${fileSize}`,
		rawSignature: `${this.secret}&${time}&/${this.version}`,
		time: time
	};
	const makePromise = () => generalUploadFile.bind(ctx)(localFile);
	return retry.retryWithPromise(makePromise);
};
const getFileDownloadLink = function(id) {
	return `${this.resourceServer}/${this.version}/${id}`;
};

const downloadFile = function(fileId, dest) {
	if (!fileId) {
		throw new Error("fileId can't be null");
	}
	if (!dest) {
		throw new Error("dest can't be null");
	}
	return new Promise((success, fail) => {
		const options = require("url").parse(getFileDownloadLink.call(this, fileId));
		options.method = "GET";
		options.headers = {
			"Accept": "application/octet-stream;charset=utf-8"
		};
		console.log("下载文件的options是", tool.inspect(options, 2));
		const protocol = options.protocol === "https:" ? "https" : "http";
		const client = require(protocol).request(options, res => {
			console.log("请求成功，即将把数据写入目的地");
			const writeStream = fs.createWriteStream(dest);
			writeStream.on("finish", () => {
				console.log("写文件完成", dest);
				success();
			});
			writeStream.on("error", e => {
				console.log("写文件出错", dest);
				fail(e);
			});
			res.pipe(writeStream);
			res.on("error", e => {
				console.error("读取文件数据出错", e);
				fail(e);
			});

		});
		client.on("error", e => {
			console.error("网络错误", e);
			fail(e);
		});
		client.end();
	});
};


const uploadImage = function(image) {
	const getImageType = function(filename) {
		const extension = tool.getFileExtension(filename);
		if (extension) {
			return `image/${extension}`;
		} else {
			return "application/octet-stream"; //不能获取文件后缀的时候就用通用的二进制流
		}
	};
	assert.ok(image, "please provide image object for upload");
	assert.ok(image.path, "please provide file path for upload");
	const filename = image.name || path.basename(image.path);
	const localFile = {
		path: image.path,
		name: filename,
		contentType: image.contentType || getImageType(filename)
	};
	const time = Date.now();
	const fileSize = fs.statSync(image.path).size;
	const ctx = {
		key: this.key,
		secret: this.secret,
		url: `${this.resourceServer}/${this.version}/images?file_size=${fileSize}`,
		rawSignature: `${this.secret}&${time}&/${this.version}/images`,
		time: time
	};
	const makePromise = () => generalUploadFile.bind(ctx)(localFile);
	return retry.retryWithPromise(makePromise);
};
const getImageLink = function(image) {
	if (!image) {
		throw new Error("image obj can't be null");
	}
	if (!image.id) {
		throw new Error("image id can't be null");
	}
	const fileId = image.id;
	const quality = image.quality ? `&quality=${image.quality}` : "";
	const rotate = image.rotate ? `&rotate=${image.rotate}` : "";
	const width = image.width ? `&width=${image.width}` : "";
	const height = image.height ? `&height=${image.height}` : "";
	const url = `${this.resourceServer}/${this.version}/images/${fileId}?1=1${quality}${rotate}${width}${height}`;
	return url;
};
module.exports = function(key, secret, resourceServer, version) {
	key = key || defaultKey;
	secret = secret || defaultSecret;
	resourceServer = tool.removeTailSlash(resourceServer) || defaultServer;
	version = version || defaultVersion;
	const ctx = {
		key,
		secret,
		resourceServer,
		version
	};
	return {
		uploadFile: uploadFile.bind(ctx),
		getFileDownloadLink: getFileDownloadLink.bind(ctx),
		downloadFile: downloadFile.bind(ctx),
		uploadImage: uploadImage.bind(ctx),
		getImageLink: getImageLink.bind(ctx)
	};
};